import csv
import time
import os
import sys
import datetime
from trading.models import *
from analysis.basic_data import *
from fundinfo.fundlist import *
from fundinfo.catch_fund_price import getNewData

MONITOR_RATE_UP = 5.0
MONITOR_RATE_DOWN = -5.0

def getDateFromStr(str):
    return datetime.datetime.strptime(str, "%Y-%m-%d %H:%M:%S").date()

def getMonthFromDay(day):
    s = str(day)
    s1 = s.rfind("-")
    return s[:s1]

def isSameMonth(month1, month2):
    return month1 == month2

def incomeMonthSortKey(income):
    return income[0]

class FundPrice:
    date = ""
    jjjz = 0.0 #基金净值
    ljjz = 0.0 #累计净值
    rate = 0.0 #日增长率
    rateYear = 0.0 #最近1年的收益
    rateYear3 = 0.0 #最近3年的收益
    rateYear5 = 0.0 #最近5年的收益

class FundIncome:
    date = None
    units = 0.0 #基金份额
    cost = 0.0 # 平均成本
    totalCost = 0.0 # 总成本
    incomeTotal = 0.0 # 累计收益
    income = 0.0 #基金收益
    incomePercent = 0.0 #收益率
    incomeDay = 0.0 #当日收益

class FundTradingData:
    date = ""
    units = 0.0
    cost = 0.0

class TradingAnalysis:
    priceDir = ""
    incomeDir = ""
    code = ""
    price = []
    income = []
    tradingData = {}
    incomeMonth = []

    def __init__(self, code):
        self.code = code
        self.price = []
        self.tradingData = {}
        self.income = []
        self.incomeMonth = []
        return

    def setBaseDir(self, dir):
        self.priceDir = dir
        return

    def setincomeDir(self, dir):
        self.incomeDir = dir
        return

    def readPriceData(self):
        path = self.priceDir + self.code + ".csv"
        csvReader = csv.reader(open(path, encoding='utf-8'))
        count = 0
        jjjz = 0.0
        ljjz = 0.0
        for line in csvReader:
            count = count + 1
            priceTmp = FundPrice()
            priceTmp.date = getDateFromStr(line[0])
            priceTmp.jjjz = float(line[1])
            priceTmp.ljjz = float(line[2])
            priceTmp.rate = self.calcRate(jjjz, ljjz, priceTmp.ljjz)
            self.price.append(priceTmp)
            jjjz = priceTmp.jjjz
            ljjz = priceTmp.ljjz
            #print(getTimeStr(priceTmp.date), priceTmp.jjjz, priceTmp.ljjz, priceTmp.rate)
        print("read", len(self.price), "price datas for trading_analysis")
        return

    def readTradingDataFromDB(self):
        datas = Trading.objects.filter(code=self.code).all().order_by("date")
        if datas == None:
            return
        
        for data in datas:
            tmp = FundTradingData()
            tmp.date = data.date
            tmp.units = data.units
            tmp.cost = data.cost
            self.tradingData[tmp.date] = tmp
            #print("read:", tmp.date, tmp.units, tmp.cost)
        print("read", len(self.tradingData), "trading items")
        return

    def readData(self):
        self.readTradingDataFromDB()
        self.readPriceData()
        return

    def calcRate(self, jjjz, ljjz1, ljjz2):
        if jjjz == 0.0:
            return 0.0

        rate = (ljjz2 - ljjz1) * 100 / jjjz
        return round(rate, 2)

    # 根据交易记录计算收益
    def calcIncome(self):
        units = 0.0
        totalCost = 0.0
        cost = 0.0
        transIncome = 0.0
        lastDayLjjz = 0.0

        for price in self.price:
            incomeDay = 0.0

            # 每日收益
            if lastDayLjjz == 0.0:
                incomeDay = 0.0
            else:
                incomeDay = (price.ljjz - lastDayLjjz) * units
            lastDayLjjz = price.ljjz

            if self.tradingData.__contains__(price.date):
                trading = self.tradingData[price.date]
                # 添加交易数据
                units = units + trading.units
                if trading.units >= 0:
                    totalCost = totalCost + trading.cost
                else :
                    totalCost = cost * units
                    transIncome = transIncome + trading.units * cost - trading.cost

            income = FundIncome()
            income.date = price.date
            income.units = units
            income.totalCost = totalCost
            if units == 0:
                income.cost = 0.0
            else:
                income.cost = totalCost / units
            cost = income.cost

            # 计算收益
            income.income = price.jjjz * income.units - income.totalCost
            income.incomeTotal = income.income + transIncome
            if income.totalCost > 0:
                income.incomePercent = income.income * 100 / income.totalCost
            else :
                income.incomePercent = 0.0

            # 格式化
            income.income = round(income.income, 2)
            income.totalCost = round(income.totalCost, 2)
            income.incomePercent = round(income.incomePercent, 2)
            income.cost = round(income.cost, 2)
            if income.units == 0.0:
                income.cost = 0.0
            income.units = round(income.units, 2)
            income.incomeTotal = round(income.incomeTotal, 2)
            income.incomeDay = round(incomeDay, 2)

            #print(income.totalCost, income.income, income.incomePercent, income.incomeTotal)

            self.income.append(income)

        #for item in self.income:
        #item = self.income[-1]
        return

    def calcMonthIncome(self):
        month1 = ""
        incomeMonth1 = 0.0
        incomeMonth2 = 0.0
        monthData = []
        lastDayIncome = 0.0
        tmpIncome = None
        for income in self.income:
            tmpIncome = income
            month2 = getMonthFromDay(income.date)
            if isSameMonth(month1, month2):
                lastDayIncome = income.incomeTotal
            else:
                incomeMonth = lastDayIncome - incomeMonth1
                incomeMonth1 = lastDayIncome
                self.incomeMonth.append([month1, round(incomeMonth,2)])
                incomeMonth = 0.0
                month1 = month2
        if tmpIncome != None:
            incomeMonth = tmpIncome.incomeTotal - incomeMonth1
            self.incomeMonth.append([month1, round(incomeMonth,2)])
        return


class TradingAnalysisTask:
    priceDir = ""
    analysisDir = ""
    incomeMonthLst = []

    def __init__(self):
        self.incomeMonthLst = []  # 要在这里初始化一次，否则多个对象会使用同一个值
        return

    def setPriceDir(self, priceDir):
        self.priceDir = priceDir
        return

    def setAnalysisDir(self, analysisDir):
        self.analysisDir = analysisDir
        return

    def analyzeAllFund(self):
        # fundLstObj = FundList()
        # fundLstObj.addFundToListByFunc(BasicData.getTradingFundBasicInfoFromDB)
        # fundLstObj.addFundToListByFunc(BasicData.getTradingFundInfoByCustomCategorys)
        # fundLst = fundLstObj.getFundList()

        # for fund in fundLst:
        #     from fundinfo.catch_fund_price import getNewData
        #     getNewData(fund.code, self.priceDir) # 更新基金价格数据
            
        #     # analysis trading
        #     analysis = TradingAnalysis(fund.code)
        #     analysis.setBaseDir(self.priceDir)
        #     analysis.readData()
        #     analysis.calcIncome()
        #     analysis.calcMonthIncome()            

        #     # code, income, incomeTotal, incomeRate
        #     income = analysis.income[-1]
        #     # trading = TradingFundInfo()
        #     # trading.code = fund.code
        #     # trading.name = fund.name
        #     # trading.risk = fund.risk
        #     # trading.type = fund.type

        #     if income != None:
        #         fund.income = income.income
        #         fund.incomeTotal = income.incomeTotal
        #         fund.incomeRate = income.incomePercent
        #         fund.cost = income.totalCost
        #         fund.units = income.units

        #     self.writeIncomeData(analysis)
        #     self.writeMonthIncomeData(analysis.incomeMonth, fund.code)
        #     self.calcTotalMonthIncome(analysis.incomeMonth)

        # #BasicData.saveTradingFundLst(tradings)
        # self.writeMonthTotalIncomeData()
        # return

        tradings = BasicData.getTradingFundLstFromDB()

        for fund in tradings:
            if fund == None or fund.code == None or fund.code == "":
                continue

            # refresh price data first
            from fundinfo.catch_fund_price import getNewData
            getNewData(fund.code, self.priceDir)
            #getAllData(fund.code, self.priceDir)
            #print('------------------')

            # analysis trading
            analysis = TradingAnalysis(fund.code)
            analysis.setBaseDir(self.priceDir)
            #analysis.setincomeDir(self.analysisDir)
            analysis.readData()
            analysis.calcIncome()
            analysis.calcMonthIncome()

            # code, income, incomeTotal, incomeRate
            if analysis.income == None or len(analysis.income) == 0:
                continue

            income = analysis.income[-1]
            if income != None:
                fund.income = income.income
                fund.incomeTotal = income.incomeTotal
                fund.incomeRate = income.incomePercent
                fund.cost = income.totalCost
                fund.units = income.units

            self.writeIncomeData(analysis)
            self.writeMonthIncomeData(analysis.incomeMonth, fund.code)
            self.calcTotalMonthIncome(analysis.incomeMonth)

        BasicData.saveTradingFundLst(tradings)
        self.writeMonthTotalIncomeData()
        return

    def writeIncomeData(self, result):
        # write to db
        print("refreshCurIncome:", result.code)
        price = result.price[-1]
        info = FundInfoBriefData()
        info.refreshCurIncome(result.code, price.date, price.rate, result.income[-1]) # 最后一个是最新的情况
        

        #write to file
        filename = self.analysisDir + "income_" + result.code + ".csv"
        with open(filename, "w", newline='') as csvfile:
            writer = csv.writer(csvfile)
            writer.writerow(["date", "jjjz", "ljjz", "rate", "units", "totalCost", \
                "cost", "incomeTotal", "income", "incomePercent", "incomeDay"])

            index = 0
            for price in result.price:
                income = result.income[index]

                writer.writerow([str(price.date), price.jjjz, price.ljjz, price.rate, income.units, income.totalCost,\
                    income.cost, income.incomeTotal, income.income, income.incomePercent, income.incomeDay])
                                
                index = index + 1
        return

    def writeMonthIncomeData(self, result, code):
        #write to db
        info = FundInfoBriefData()
        info.refreshMonthIncome(code, result)

        #write to file
        filename = self.analysisDir + "month_income_" + code + ".csv"
        with open(filename, "w", newline='') as csvfile:
            writer = csv.writer(csvfile)
            writer.writerow(["month", "income"])

            for income in result:
                writer.writerow([income[0], income[1]])
        return

    def calcTotalMonthIncome(self, incomeMonth):
        for a in incomeMonth:
            find = False
            for b in self.incomeMonthLst:
                if a[0] == b[0]:
                    b[1] = a[1] + b[1]
                    find = True
                    break

            if find == False:
                self.incomeMonthLst.append(a)
        self.incomeMonthLst.sort(key=incomeMonthSortKey)
        return

    def writeMonthTotalIncomeData(self):
        data = self.incomeMonthLst
        c = len(self.incomeMonthLst)
        if c > 24:
            data = self.incomeMonthLst[c - 24 -1:]

        filename = self.analysisDir + "month_income.csv"
        with open(filename, "w", newline='') as csvfile:
            writer = csv.writer(csvfile)
            writer.writerow(["month", "income"])

            for income in data:
                income[1] = round(income[1], 2)
                writer.writerow(income)
        return